﻿// Turtle Graphics
//===============================================================================
// Copyright 2009 Jason Hogg.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Xml;
using TurtleGraphics;
// WpfLogo.Window1
namespace WpfLogo
{
    /// <summary>
    /// WPF form for editing and displaying Logo programs and
    /// displaying the graphical outpu
    /// </summary>
    public partial class Window1 : Window
    {
        private int angle = 0;
        private int x = 200;
        private int y = 200;

        string grammar = @"SIMPLE COMMANDS" + Environment.NewLine +
                          "MoveTo [x,y]  - Move the turtle to absolute position x, y " + Environment.NewLine +
                          "Move [x,y]    - Move the turtle relative to the current position " + Environment.NewLine +
                          "Draw [n]      - Draw a line from the current position n pixels " + Environment.NewLine +
                          "Rotate [n]    - Rotate the turtle n degrees, where n is between -360 and +360 " + Environment.NewLine +
                          "Color [color] - Select a color: Red, Blue, Green, Yellow, White, Black" + Environment.NewLine +
                          Environment.NewLine + "LOOPS " + Environment.NewLine +
                          "Loop [n] { [Program] } - Run the Logo program n times" + Environment.NewLine +
                          Environment.NewLine + "FUNCTIONS " + Environment.NewLine +
                          "Function [FunctionName] { [Program] } - Declares a function called function name containing logo program" + Environment.NewLine +
                          "Call [FunctionName] - Calls the previously declared function called FunctionName";

        public Window1()
        {
            InitializeComponent();

            grammarSummary.Content = grammar;
            grammarTitle.FontSize = 13;

            // Read default Logo program 
            StreamReader sr = new StreamReader(@"LogoSamples\Input.logo");
            logoProgramText.Text = sr.ReadToEnd();
            sr.Close();
            ExecuteLogoProgram(logoProgramText.Text);
        }

        private void ExecuteLogoProgram(string inputProgram)
        {
            // Clear previous errors
            errorMessage.Text = "";

            // Run the lexer and parser
            TurtleGraphicsParser parser = new TurtleGraphicsParser("Logo.mx", "Languages.Logo", inputProgram);
            object rootNode = new object();
            string commands = string.Empty;
            try
            {
                rootNode = parser.Parse();
                commands = parser.EnumerateOutputTree(rootNode);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception occurred parsing: " + ex.Message);
                errorMessage.Text = ex.Message.ToString();
            }

            // Run the output through an interpreter to generate our
            // WPF program
            LogoData parsedLogo = new LogoData();
            TurtleGraphicsInterpreter interpreter = new TurtleGraphicsInterpreter(commands);
            interpreter.Angle = angle;
            interpreter.X = x;
            interpreter.Y = y; 
            try
            {
                // TODO: Verify naming conventions - not sure if parsedLogo is the correct term here - it is probably interpreted output
                parsedLogo.ParsedLogo = interpreter.Interpret();
                textBox2.Text = parsedLogo.ParsedLogo.Replace("  ", " ");          // Output generated XAML
                textBox3.Text = parser.LogoTrace.ToString();                       // Trace of Mg AST being processed

                // Take the string generated by our interpreter and translate into
                // a XAML based Geometric Path and add to our drawing grid
                StringReader stringReader = new StringReader(parsedLogo.ParsedLogo);
                XmlReader xmlReader = XmlReader.Create(stringReader);
                //System.Windows.Shapes.Path readerLoadPath = (System.Windows.Shapes.Path)System.Windows.Markup.XamlReader.Load(xmlReader);

                // jasons experiment to support multiple path statements 
                System.Windows.Controls.Grid readerLoadPath = (System.Windows.Controls.Grid)System.Windows.Markup.XamlReader.Load(xmlReader);
                
                drawingGrid.Children.Add(readerLoadPath);
                
                // Rotate our little turtle
                angle = interpreter.Angle;
                x = interpreter.X;
                y = interpreter.Y;

                // Move the little guy
                int turtleLead = 15;
                // TODO: Move this code into a function
                int turtleX = Convert.ToInt32(x + (turtleLead * Math.Sin(ConvertDegreesToRadians(angle)))); // SOH-CAH-TOA
                int turtleY = Convert.ToInt32(y + (turtleLead * Math.Cos(ConvertDegreesToRadians(angle))));
                Canvas.SetLeft(turtle, turtleX - 25);
                Canvas.SetTop(turtle, turtleY - 25);

                RotateTransform rt = new RotateTransform(-1 * angle, Canvas.GetLeft(turtle) + 25, Canvas.GetTop(turtle) + 25);
                turtleGrid.RenderTransform = rt;
                
                Console.WriteLine("Line X = " + x);
                Console.Write("Line Y = " + y);

                Console.WriteLine("turtleGrid h = " + turtleGrid.ActualHeight);
                Console.WriteLine("turtleGrid w = " + turtleGrid.ActualWidth);

                Console.WriteLine("Turtle X = " + Canvas.GetLeft(turtle));
                Console.Write("Turtle Y = " + Canvas.GetTop(turtle));

            }
            catch (Exception ex)
            {
                textBox2.Text = "An exception occured passing your program. Please correct and resubmit. Error = " + ex.Message + ". Inner = " + ex.InnerException.Message;
            }

        }


        // Run the Logo Program
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            ExecuteLogoProgram(logoProgramText.Text);
        }

        // Clear the output drawing grid
        private void button2_Click(object sender, RoutedEventArgs e)
        {
            drawingGrid.Children.Clear();
            drawingGrid.Children.Add(turtleGrid);
        }

        // File / New
        private void button3_Click(object sender, RoutedEventArgs e)
        {
            logoProgramText.Clear();
        }

        // TODO: Move this into a separate class
        // Sin and Cos functions work in Radians
        private Double ConvertDegreesToRadians(Double degrees)
        {
            return degrees * (Math.PI / 180);
        }


        private void immediateMode_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (immediateMode.Text.Contains(System.Environment.NewLine))
            {
                ExecuteLogoProgram(immediateMode.Text);
                logoProgramText.Text += immediateMode.Text + System.Environment.NewLine;
                immediateMode.Text = "";
            }

        }

        private void button4_Click(object sender, RoutedEventArgs e)
        {
            logoProgramText.Text += immediateMode.Text + Environment.NewLine;
            ExecuteLogoProgram(immediateMode.Text);
        }

        private void richTextBox1_TextChanged(object sender, TextChangedEventArgs e)
        {

        }

    }

    public class LogoData
    {
        public LogoData() { }

        private string parsedLogo;

        public string ParsedLogo
        {
            get { return parsedLogo; }
            set { parsedLogo = value; }
        }
    }
}
